#include "mb_hci.h"

/* hci 私有数据初始化 */
hci_prvt s_hci_prvt = 
{
    .check_timeout = {0, 0},
    .action_status = {MB_UNKNOWN_DEF, MB_UNKNOWN_DEF, \
                      MB_UNKNOWN_DEF, MB_UNKNOWN_DEF},
};

/* 开始接收用户指令 */
static int hci_prvt_start_recv(void)
{
    cmc_op *    carrier_op;
    mb_buf_attr buf_attr;
    
    /* 获得 数据通道操作函数接口 */
    carrier_op = s_hci_prvt.carrier;

    if (carrier_op == NULL)
    {
        return -1;
    }

    /* 通过通道接收数据 */
    if (s_hci_prvt.action_status.is_start_recv != MB_TRUE)
    {
        /* 设置人机交互的接收缓冲区信息 */
        buf_attr.buf = s_hci_prvt.rx_buf;
        buf_attr.len = sizeof(s_hci_prvt.rx_buf);
        s_hci_prvt.carrier->set_rxbuf_attr(&buf_attr);

        carrier_op->start_recv();    /* 开始接收数据 */
        s_hci_prvt.action_status.is_start_recv = MB_TRUE;
    }
    
    return 0;
}

/* 复位接收指令动作的状态 */
static void hci_prvt_reset_recv_status(void)
{
    /* 通过通道接收数据 */
    s_hci_prvt.action_status.is_start_recv = MB_FALSE;

    return;
}

/* 判断是否收到指令 */
static MB_STATUS hci_prvt_check_is_rxed(void)
{
    MB_STATUS is_rxed;
    cmc_op *  carrier_op;

    /* 获得 数据通道操作函数接口 */
    carrier_op = s_hci_prvt.carrier;

    if (carrier_op == NULL)
    {
        return MB_FALSE;
    }

    /* 获得是否收到数据的状态 */
    is_rxed = carrier_op->check_is_rxed();

    return is_rxed;
}

/* 获取接收到的数据 */
static mb_buf_attr *hci_prvt_get_data(void)
{
    cmc_op *      carrier_op;
    mb_buf_attr * buf_attr = NULL;

    /* 获得 数据通道操作函数接口 */
    carrier_op = s_hci_prvt.carrier;

    if (carrier_op == NULL)
    {
        return NULL;
    }

    /* 获取接收到的数据 */
    buf_attr = carrier_op->get_data();

    return buf_attr;
}

/* 检测用户是否请求中止输入(重新) */
static hci_req *hci_prvt_check_reselect(mb_buf_attr * buf_attr)
{
    /* 参数检查 */
    if (buf_attr == NULL)
    {
        return NULL;
    }

    /* 判断是否收到了退出指令 */
    if (buf_attr->buf[0] != HCI_EXIT_CUR_INPUT)
    {
        s_hci_prvt.reqs.is_reselect = MB_FALSE;
        return NULL;
    }

    /* 标记用户请求重新输入 */
    s_hci_prvt.reqs.is_reselect = MB_TRUE;

    return &s_hci_prvt.reqs;
}

/* 从指令中解析出用户的指令请求 */
static hci_req * hci_prvt_parse(mb_buf_attr * buf_attr, MB_STATUS * ack_status)
{
    hci_format    format;

    /* 参数判断 */
    if (buf_attr == NULL)
    {
        return NULL;
    }

    /* 将接收到的指令适配标准格式 */
    memset(&format, 0, sizeof(format));
    memcpy(&format, buf_attr->buf, buf_attr->len);

    /* 解析1级请求 */
    switch (format.cmd_1st)
    {
        /* 选择 PROT 数据协议 */
        case HCI_1ST_REQ_SELECT_PROT:
        {
            /* 先判断指令有效性 */
            if ((format.or1 != HCI_REQ_OR_MARK) || \
                ((format.cmd_2nd < HCI_2ND_REQ_PROT_XMODEM) || \
                 (format.cmd_2nd > HCI_2ND_REQ_PROT_UNKNOWN)))
                 {
                    return NULL;
                 }

            /* 请求项个数和所有请求 */
            s_hci_prvt.reqs.nbr  = 2;   /* 请求项个数 */
            s_hci_prvt.reqs.bits = (HCI_1ST_REQ_BIT_DOMAIN(HCI_1ST_REQ_SELECT_PROT)) | \
                                   (HCI_2ND_REQ_BIT_DOMAIN(format.cmd_2nd));
        } break;

        /* 选择 CMC 设备 */
        case HCI_1ST_REQ_SELECT_CMC:
        {
            /* 先判断指令有效性 */
            if ((format.or1 != HCI_REQ_OR_MARK) || \
                ((format.cmd_2nd < HCI_2ND_REQ_CMC_UART) || \
                 (format.cmd_2nd > HCI_2ND_REQ_CMD_UNKNOWN)))
                 {
                    return NULL;
                 }

            /* 请求项个数和所有请求 */
            s_hci_prvt.reqs.nbr  = 2;   /* 请求项个数 */
            s_hci_prvt.reqs.bits = (HCI_1ST_REQ_BIT_DOMAIN(HCI_1ST_REQ_SELECT_CMC)) | \
                                   (HCI_2ND_REQ_BIT_DOMAIN(format.cmd_2nd));
        } break;

        /* 选择 STO 设备 */
        case HCI_1ST_REQ_SELECT_STO:
        {
             /* 先判断指令有效性 */
            if ((format.or1 != HCI_REQ_OR_MARK) || \
                (format.or2 != HCI_REQ_OR_MARK) || \
                ((format.cmd_2nd < HCI_2ND_REQ_STO_ROM) || \
                 (format.cmd_2nd > HCI_2ND_REQ_STO_UNKNOWN)) || \
                ((format.cmd_3rd != HCI_3RD_REQ_STO_DNOTERASE) && \
                 (format.cmd_3rd != HCI_3RD_REQ_STO_ERASE)))
                 {
                    return NULL;
                 }

            /* 请求项个数和所有请求 */
            s_hci_prvt.reqs.nbr  = 3;   /* 请求项个数 */
            s_hci_prvt.reqs.bits = (HCI_1ST_REQ_BIT_DOMAIN(HCI_1ST_REQ_SELECT_STO)) | \
                                   (HCI_2ND_REQ_BIT_DOMAIN(format.cmd_2nd)) | \
                                   (HCI_3RD_REQ_BIT_DOMAIN(format.cmd_3rd));
        } break;

        /* 升级固件 */
        case HCI_1ST_REQ_UPDATE_FW:
        {
            /* 请求项个数和所有请求 */
            s_hci_prvt.reqs.nbr  = 1;   /* 请求项个数 */
            s_hci_prvt.reqs.bits = HCI_1ST_REQ_BIT_DOMAIN(HCI_1ST_REQ_UPDATE_FW);
        } break;

        /* 进入APP */
        case HCI_1ST_REQ_ENTRY_APP:
        {
            /* 请求项个数和所有请求 */
            s_hci_prvt.reqs.nbr  = 1;   /* 请求项个数 */
            s_hci_prvt.reqs.bits = HCI_1ST_REQ_BIT_DOMAIN(HCI_1ST_REQ_ENTRY_APP);
        } break;

        /* 系统重启 */
        case HCI_1ST_REQ_RESET:
        {
            /* 请求项个数和所有请求 */
            s_hci_prvt.reqs.nbr  = 1;   /* 请求项个数 */
            s_hci_prvt.reqs.bits = HCI_1ST_REQ_BIT_DOMAIN(HCI_1ST_REQ_RESET);
        } break;

        /* 退出EXIT_BOOT */
        case HCI_1ST_REQ_EXIT_BOOT:
        {
            /* 请求项个数和所有请求 */
            s_hci_prvt.reqs.nbr  = 1;   /* 请求项个数 */
            s_hci_prvt.reqs.bits = HCI_1ST_REQ_BIT_DOMAIN(HCI_1ST_REQ_EXIT_BOOT);
        } break;
    
    default:
        return NULL;
        break;
    }

    return &s_hci_prvt.reqs;
}

/* 对用户输入指令作出应答 */
static int hci_prvt_send_ack_status(MB_STATUS is_ack)
{
    cmc_op *      carrier_op;
    mb_buf_attr * txbuf_attr;
    mb_buf_attr   buf_attr;

    /* 获得 数据通道操作函数接口 */
    carrier_op = s_hci_prvt.carrier;

    if (carrier_op == NULL)
    {
        return -1;
    }

    /* 设置发送缓冲区信息 */
    buf_attr.buf = s_hci_prvt.tx_buf;
    buf_attr.len = sizeof(s_hci_prvt.tx_buf);
    s_hci_prvt.carrier->set_txbuf_attr(&buf_attr);

    /* 获得发送缓冲区信息 */
    txbuf_attr = carrier_op->get_txbuf();

    if (txbuf_attr == NULL)
    {
        return -1;
    }

    /* 填充指令数据 */
    memcpy(txbuf_attr->buf, \
           (is_ack == MB_TRUE) ? HCI_RESPONSE_SUCC : \
                                 HCI_RESPONSE_FAIL,
           HCI_RESPONSE_LEN);
    txbuf_attr->len = HCI_RESPONSE_LEN;

    /* 通过数据通道发出 */
    carrier_op->put_data(txbuf_attr);
    
    return 0;
}

/* 输出倒计时提示信息 */
static void hci_prvt_delay_notice_show(MB_STATUS SHOW_NOTICE)
{
    cmc_op *      carrier_op;
    mb_buf_attr * txbuf_attr;
    uint32_t      len_size = 0;
    mb_buf_attr   buf_attr;

    /* 判断是否需要输出倒计时提示信息 */
    if (SHOW_NOTICE == MB_FALSE)
    {
        return;
    }

    /* 只显示一次 */
    if (s_hci_prvt.action_status.is_delay_noticed != MB_TRUE)
    {
        /* 获得 数据通道操作函数接口 */
        carrier_op = s_hci_prvt.carrier;

        if (carrier_op == NULL)
        {
            return;
        }

        /* 设置发送缓冲区信息 */
        buf_attr.buf = s_hci_prvt.tx_buf;
        buf_attr.len = sizeof(s_hci_prvt.tx_buf);
        s_hci_prvt.carrier->set_txbuf_attr(&buf_attr);

        /* 获得发送缓冲区信息 */
        txbuf_attr = carrier_op->get_txbuf();

        if (txbuf_attr == NULL)
        {
            return;
        }

        /* 填充提示内容 */
        len_size = HCI_DELAY_NOTICE_LEN;
        memcpy(txbuf_attr->buf, \
               HCI_DELAY_NOTICE, len_size);

        /* 通过数据通道发出(显示到终端) */
        txbuf_attr->len = len_size;
        carrier_op->put_data(txbuf_attr);

        /* 标记已显示过延时提醒 */
        s_hci_prvt.action_status.is_delay_noticed = MB_TRUE;
    }

    return;
}

/* --------------------------------------------------------------- */

/* 初始化人机交互通信通道 */
static int hci_op_carrier_init(cmc_op *op)
{
    /* 为 用户交互 指定数据通道的操作接口 */
    s_hci_prvt.carrier = op;

    if (s_hci_prvt.carrier == NULL)
    {
        return -1;
    }

    return 0;
}

/* 等待用户主动打断事件 */
static MB_STATUS hci_op_wait_abort(MB_STATUS SHOW_NOTICE)
{
    int           ret;
    MB_STATUS     RSTATUS;
    mb_buf_attr * buf_attr;

    /* 显示倒计时提示信息 (允许显示, 则只会提示1次) */
    hci_prvt_delay_notice_show(SHOW_NOTICE);

    /* 接收用户指令 */
    ret = hci_prvt_start_recv();

    if (ret != 0)
    {
        return MB_FALSE;
    }

    /* 判断是否收到指令 */
    RSTATUS = hci_prvt_check_is_rxed();

    if (RSTATUS != MB_TRUE)
    {
        return MB_FALSE;
    }

    /* 获取指令数据 */
    buf_attr = hci_prvt_get_data();

    if (buf_attr == NULL)
    {
        RSTATUS = MB_FALSE;
        goto HCI_WAIT_BOARD_HANDLER;
    }

    /* 解析数据 */
    if ((buf_attr->len != 1) || \
        (buf_attr->buf[0] != HCI_DELAY_ABORT_KEY))
    {
        RSTATUS = MB_FALSE;
        goto HCI_WAIT_BOARD_HANDLER;
    }

    /* 收到用户打断指令 */
    RSTATUS = MB_TRUE;

HCI_WAIT_BOARD_HANDLER:
    /* 已收到打断指令, 复位接收状态 */
    hci_prvt_reset_recv_status();

    return RSTATUS;
}

/* 菜单显示 */
static int hci_op_menu_show(void)
{
    cmc_op *      carrier_op;
    mb_buf_attr * txbuf_attr;
    uint32_t      offset = 0, len_size = 0;
    mb_buf_attr   buf_attr;

    /* 获得 数据通道操作函数接口 */
    carrier_op = s_hci_prvt.carrier;

    if (carrier_op == NULL)
    {
        return -1;
    }

    /* 设置发送缓冲区信息 */
    buf_attr.buf = s_hci_prvt.tx_buf;
    buf_attr.len = sizeof(s_hci_prvt.tx_buf);
    s_hci_prvt.carrier->set_txbuf_attr(&buf_attr);

    /* 获得发送缓冲区信息 */
    txbuf_attr = carrier_op->get_txbuf();

    if (txbuf_attr == NULL)
    {
        return -1;
    }

    /* 填充菜单项 */
    offset = 0;

    len_size = sizeof("\n\n");
    memcpy((txbuf_attr->buf + offset), "\n\n", len_size);
    offset += len_size;

    len_size = sizeof("================= MBOOT MENU =================\n");
    memcpy((txbuf_attr->buf + offset), \
           "================= MBOOT MENU =================\n", len_size);
    offset += len_size;

    len_size = sizeof("[1]选择数据 解析 协议(位或对应数字)\n");
    memcpy((txbuf_attr->buf + offset), \
           "[1]选择数据 解析 协议(位或对应数字)\n", len_size);
    offset += len_size;

    len_size = sizeof(PROT_HCI_TYPE_LIST);
    memcpy((txbuf_attr->buf + offset), \
           PROT_HCI_TYPE_LIST, len_size);
    offset += len_size;

    len_size = sizeof("[2]选择数据 通信 载体, 如下(位或对应数字):\n");
    memcpy((txbuf_attr->buf + offset), \
           "[2]选择数据 通信 载体, 如下(位或对应数字):\n", len_size);
    offset += len_size;

    len_size = sizeof(CMC_HCI_DEV_LIST);
    memcpy((txbuf_attr->buf + offset), \
           CMC_HCI_DEV_LIST, len_size);
    offset += len_size;

    len_size = sizeof("[3]选择数据 存储 载体(位或对应数字)\n");
    memcpy((txbuf_attr->buf + offset), \
           "[3]选择数据 存储 载体(位或对应数字)\n", len_size);
    offset += len_size;

    len_size = sizeof(STO_HCI_DEV_LIST);
    memcpy((txbuf_attr->buf + offset), \
           STO_HCI_DEV_LIST, len_size);
    offset += len_size;

    len_size = sizeof("   (0: 擦除, 1: 不擦除)\n");
    memcpy((txbuf_attr->buf + offset), \
           "   (0: 擦除, 1: 不擦除)\n", len_size);
    offset += len_size;

    len_size = sizeof("[4]更新固件\n");
    memcpy((txbuf_attr->buf + offset), \
           "[4]更新固件\n", len_size);
    offset += len_size;

    len_size = sizeof("[5]进入系统\n");
    memcpy((txbuf_attr->buf + offset), \
           "[5]进入系统\n", len_size);
    offset += len_size;

    len_size = sizeof("[6]重启\n");
    memcpy((txbuf_attr->buf + offset), \
           "[6]重启\n", len_size);
    offset += len_size;

    len_size = sizeof("[7]退出\n");
    memcpy((txbuf_attr->buf + offset), \
           "[7]退出\n", len_size);
    offset += len_size;

    len_size = sizeof("\n\n输入选择: ");
    memcpy((txbuf_attr->buf + offset), \
           "\n\n输入选择: ", len_size);
    offset += len_size;

    /* 通过数据通道发出(显示到终端) */
    txbuf_attr->len = offset;
    carrier_op->put_data(txbuf_attr);

    return 0;
}

/* 处理用户输入选择 */
static hci_req * hci_op_select_parse(void)
{
    int            ret;
    MB_STATUS      RSTATUS, ack_status = MB_FALSE;
    mb_buf_attr *  buf_attr;
    hci_req *      p_req = NULL;

    /* 接收用户指令 */
    ret = hci_prvt_start_recv();

    if (ret != 0)
    {
        return NULL;
    }

    /* 判断是否收到指令 */
    RSTATUS = hci_prvt_check_is_rxed();

    if (RSTATUS != MB_TRUE)
    {
        return NULL;
    }

    /* 获得数据 */
    buf_attr = hci_prvt_get_data();

    if (buf_attr == NULL)
    {
        goto HCI_SELECT_PARSE_HANDLER;
    }

    /* 检测用户是否请求中止输入(重新) */
    p_req = hci_prvt_check_reselect(buf_attr);

    if (p_req != NULL)
    {
        goto HCI_SELECT_PARSE_EXIT;
    }

    /* 缓存用户输入的指令 */
    memcpy((s_hci_prvt.req_cmd.buf + s_hci_prvt.req_cmd.len), \
           buf_attr->buf, buf_attr->len);
    s_hci_prvt.req_cmd.len += buf_attr->len;

    /* 解析数据 */
    p_req = hci_prvt_parse(&s_hci_prvt.req_cmd, &ack_status);

    if (p_req == NULL)
    {
        goto HCI_SELECT_PARSE_HANDLER;
    }

HCI_SELECT_PARSE_EXIT:
    /* 接收完了一个完整的指令 / 需要重新输入, 清空缓存区 */
    memset(s_hci_prvt.req_cmd.buf, 0, \
           sizeof(s_hci_prvt.req_cmd_buf));
    s_hci_prvt.req_cmd.len = 0;

HCI_SELECT_PARSE_HANDLER:
    /* 复位接收状态 */
    hci_prvt_reset_recv_status();

    return p_req;
}

/* 反馈用户操作结果 */
static MB_STATUS hci_op_response(MB_STATUS OP_RESULT)
{
    int ret;

    /* 用户输入指令反馈 */
    ret = hci_prvt_send_ack_status(OP_RESULT);

    if (ret != 0)
    {
        return MB_FALSE;
    }

    return MB_TRUE;
}

/* 检测行为在指定时间后是否超时 */
static MB_STATUS hci_op_check_is_timeout(uint32_t timeout)
{
    /* 参数检测 */
    if (timeout == MB_MAX_NBR)
    {
        s_hci_prvt.check_timeout.settick = 0;
        return MB_FALSE;    /* 即为关闭超时检测 */
    }

    /* 获得当前的系统tick */
    s_hci_prvt.check_timeout.curtick = HAL_GetTick();

    /* 设置超时tick */
    if (s_hci_prvt.check_timeout.settick == 0)
    {
        /* 1tick = 1ms */
        s_hci_prvt.check_timeout.settick = s_hci_prvt.check_timeout.curtick + \
                                           (timeout * 1000);
    }

    /* 判断是否超时 */
    if (s_hci_prvt.check_timeout.curtick >= \
        s_hci_prvt.check_timeout.settick)
        {
            return MB_TRUE;
        }

    /* 返未超时 */
    return MB_FALSE;
}

/* 用户交互相关操作 */
hci_op s_hci_op = 
{
    .carrier_init     = hci_op_carrier_init,
    .wait_abort       = hci_op_wait_abort,
    .menu_show        = hci_op_menu_show,
    .select_parse     = hci_op_select_parse,
    .response         = hci_op_response,
    .check_is_timeout = hci_op_check_is_timeout,
};

/* 注册 prot 协议操作 */
hci_op_t mb_hci_op_register(void)
{
    /* 初始化部分私有变量 */
    s_hci_prvt.req_cmd.buf = s_hci_prvt.req_cmd_buf;
    s_hci_prvt.req_cmd.len = 0;

    return &s_hci_op;
}
